﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using GestorSQL.BLL;
using GestorSQL.BusinessEntities;
using System.Threading;
using GestorSQL.BLL.QueryExecutions;

namespace GestorSQL.Service.Windows.AutomaticExecute
{
    public partial class GestorSQLExecuteService : ServiceBase
    {

        #region Variables Privadas
        private bool procesing = false;
        private System.Timers.Timer timmer;
        #endregion

        #region Constructores
        public GestorSQLExecuteService()
        {
            InitializeComponent();
        }

        #endregion

        #region Eventos

        void timmer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            procesing = true;
            CaseManager cManager = new CaseManager();
            List<Caso> casos = cManager.GetCaseList(Role.SISTEMA, new string[] { Role.SISTEMA });
            if (casos.Count == 0)
            {
                procesing = false;
                return;
            }
            int count = 0;
            ManualResetEvent[] doneEvents = new ManualResetEvent[casos.Count];
            foreach (Caso caso in casos)
            {
                doneEvents[count] = new ManualResetEvent(false);
                CommandCallback callback = new CommandCallback(caso, doneEvents[count]);
                ThreadPool.QueueUserWorkItem(callback.Execute, count++);
            }
            WaitHandle.WaitAll(doneEvents);

            procesing = false;
        }

        #endregion

        #region Metodos Protegidos
        protected override void OnStart(string[] args)
        {
#if (DEBUG)
            System.Threading.Thread.Sleep(40000);
#endif
            timmer = new System.Timers.Timer();
            timmer.Elapsed += new System.Timers.ElapsedEventHandler(timmer_Elapsed);
            timmer.Interval = _GetTimmerInterval(); ;
            timmer.Enabled = true;
        }

        protected override void OnStop()
        {
            if (procesing)
                EventLog.WriteEntry("El servicio se detuvo mientras ejecutaba uno o varios casos");
            timmer.Enabled = false;
        }
        #endregion

        #region Metodos Privados
        private int _GetTimmerInterval()
        {
            int interval = 300000;
            ParameterManager pManager = new ParameterManager();
            string sInterval = pManager.GetParameter("ServiceTimerInterval").ToString();
            string endSInterval = sInterval.Substring(sInterval.Length - 1).ToUpper();
            string numSInterval = sInterval.Substring(0, sInterval.Length - 1);
            int iNumSInterval = -1;
            int.TryParse(numSInterval, out iNumSInterval);
            if (iNumSInterval == -1)
            {
                iNumSInterval = 5;
                endSInterval = "M";
            }
            switch (endSInterval)
            {
                case "S":
                    interval = 1000 * iNumSInterval;
                    break;
                case "M":
                    interval = 1000 * 60 * iNumSInterval;
                    break;
                case "H":
                    interval = 1000 * 60 * 60 * iNumSInterval;
                    break;
            }
            return interval;
        }

        #endregion
    }

    class CommandCallback
    {
        #region Variables Privadas
        private Caso _caso { get; set; }
        private ManualResetEvent _doneEvent;
        #endregion

        #region Constructores
        public CommandCallback(Caso caso, ManualResetEvent doneEvent)
        {
            _caso = caso;
            _doneEvent = doneEvent;
        }
        #endregion

        #region Metodos Publicos
        public void Execute(Object threadContext)
        {
            CaseManager cManager = new CaseManager();
            SolutionManager solutionManager = new SolutionManager();

            try
            {
                cManager.SetStateCase(_caso, string.Format("Inicio Ejecucion Automatica ({0})", DateTime.Now.ToString()), EstadoCaso.InicioEjecucionAutomatica);
                SolutionManager _solutionManager = new SolutionManager();
                string query = _solutionManager.GetOriginalSolution(_caso.NumeroCaso, _caso.SolucionActual.Value);

                using (BLLCommand bllCommand = new BLLCommand(_caso))
                {
                    try
                    {
                        bllCommand.OpenConnection();
                        bllCommand.BeginTransaction();
                        bllCommand.ComentarioEjecucion = string.Empty;

                        BLLReader reader = bllCommand.ExecuteQuery(query);
                        do
                        {
                            if (reader.ResultType == ResulType.Fail)
                                throw new Exception(reader.Message);
                            else if (reader.ResultType == ResulType.Select)
                            {
                                while (reader.Read())
                                    reader.GetRowData();
                            }
                        } while (reader.NextResult());
                        bllCommand.CommitTransaction();
                    }
                    catch (Exception ex)
                    {
                        bllCommand.RollbackTransaction();
                        throw ex;
                    }
                }
                //cManager.SetStateCase(_caso, "Fin Ejecucion Automatica", EstadoCaso.EjecutadoCorrectamente);
                solutionManager.CerrarSolucion(_caso.NumeroCaso, "Fin Ejecucion Automatica");


            }
            catch (Exception ex)
            {
                cManager.SetStateCase(_caso, "Ocurrio un error en la ejecucion: /n" + ex.ToString(), EstadoCaso.EjecutadoError);
                cManager.SetStateCase(_caso, "Ocurrio un error en la ejecucion: /n" + ex.ToString(), EstadoCaso.DevueltoDesdeEjecucion);
            }
            finally
            {
                _doneEvent.Set();
            }
        }

        private void _ExecuteQuery()
        {
        }
        #endregion
    }
}
